#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <fstream>
#include <sstream>
#include <cstring>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#endif

#include "data_codec.h"

// 日志模块
class Logger {
public:
    Logger(const std::string& filename) {
        logfile.open(filename, std::ios::out | std::ios::app);
        if (!logfile.is_open()) {
            throw std::runtime_error("Failed to open log file");
        }
    }

    ~Logger() {
        if (logfile.is_open()) {
            logfile.close();
        }
    }

    void log(const std::string& message) {
        std::lock_guard<std::mutex> lock(log_mtx);
        std::cout << message << std::endl;    // 输出到终端
        logfile << message << std::endl;      // 输出到文件
    }

private:
    std::ofstream logfile;
    std::mutex log_mtx;
};

// 串口数据接收处理类
class SerialReceiver {
public:
    SerialReceiver(const std::string& port_name, int baud_rate = 115200, bool ctsrts = false, const std::string& log_filename = "serial_test.log")
        : port_name(port_name), baud_rate(baud_rate), ctsrts(ctsrts), running(true), logger(log_filename) {
        openPort();
        read_thread = std::thread(&SerialReceiver::readLoop, this);
    }

    ~SerialReceiver() {
        running = false;
        if (read_thread.joinable()) {
            read_thread.join();
        }
        closePort();
    }

private:
    std::string port_name;
    int baud_rate;
    bool ctsrts;
    std::thread read_thread;
    std::atomic<bool> running;
    DataCodec codec;
    std::mutex mtx;
    std::vector<uint16_t> received_sequences; // 使用 vector 以保证插入顺序
    Logger logger;

#ifdef _WIN32
    HANDLE hComm;
#else
    int fd;
#endif

    void openPort() {
#ifdef _WIN32
        hComm = CreateFile(port_name.c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
        if (hComm == INVALID_HANDLE_VALUE) {
            throw std::runtime_error("Failed to open port");
        }

        DCB dcb = { 0 };
        dcb.DCBlength = sizeof(dcb);
        if (!GetCommState(hComm, &dcb)) {
            CloseHandle(hComm);
            throw std::runtime_error("Failed to get port attributes");
        }

        dcb.BaudRate = baud_rate;
        dcb.ByteSize = 8;
        dcb.StopBits = ONESTOPBIT;
        dcb.Parity = NOPARITY;
        dcb.fRtsControl = ctsrts ? RTS_CONTROL_HANDSHAKE : RTS_CONTROL_DISABLE;

        if (!SetCommState(hComm, &dcb)) {
            CloseHandle(hComm);
            throw std::runtime_error("Failed to set port attributes");
        }

#else
        fd = open(port_name.c_str(), O_RDWR | O_NOCTTY | O_SYNC);
        if (fd < 0) {
            throw std::runtime_error("Failed to open port");
        }

        struct termios tty;
        memset(&tty, 0, sizeof tty);
        if (tcgetattr(fd, &tty) != 0) {
            close(fd);
            throw std::runtime_error("Failed to get port attributes");
        }

        cfmakeraw(&tty);

        tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
        tty.c_iflag &= ~IGNBRK;
        tty.c_lflag = 0;
        tty.c_oflag = 0;
        tty.c_cc[VMIN] = 1;
        tty.c_cc[VTIME] = 5;
        tty.c_cflag |= (CLOCAL | CREAD);

        if (ctsrts) {
            tty.c_cflag |= CRTSCTS;
        } else {
            tty.c_cflag &= ~CRTSCTS;
        }

        tty.c_cflag &= ~(PARENB | PARODD);
        tty.c_cflag &= ~CSTOPB;

        if (baud_rate == 1000000) {
            cfsetispeed(&tty, B1000000);
            cfsetospeed(&tty, B1000000);
        } else {
            cfsetispeed(&tty, baud_rate);
            cfsetospeed(&tty, baud_rate);
        }

        if (tcsetattr(fd, TCSANOW, &tty) != 0) {
            close(fd);
            throw std::runtime_error("Failed to set port attributes");
        }
#endif
    }

    void closePort() {
#ifdef _WIN32
        CloseHandle(hComm);
#else
        close(fd);
#endif
    }

    void readLoop() {
        uint8_t buffer[256];
        while (running) {
#ifdef _WIN32
            DWORD bytesRead;
            if (ReadFile(hComm, buffer, sizeof(buffer), &bytesRead, NULL)) {
                if (bytesRead > 0) {
                    std::vector<uint8_t> data(buffer, buffer + bytesRead);
                    auto packets = codec.decode(data);
                    processPackets(packets);
                }
            }
#else
            int n = read(fd, buffer, sizeof(buffer));
            if (n > 0) {
                std::vector<uint8_t> data(buffer, buffer + n);
                auto packets = codec.decode(data);
                processPackets(packets);
            }
#endif
        }
    }

    bool isNextSequence(uint16_t current, uint16_t next) {
        return (current + 1) % 65536 == next;
    }

    void processPackets(const std::vector<std::unique_ptr<pkt_t>>& packets) {
        std::lock_guard<std::mutex> lock(mtx);
        for (const auto& pkt : packets) {
            received_sequences.push_back(pkt->seq); // 保持插入顺序
            std::ostringstream oss;
            oss << "Received Packet: " << std::endl;
            oss << "Header: " << std::hex << pkt->header << std::endl;
            oss << "Length: " << std::dec << pkt->len << std::endl;
            oss << "CRC: " << pkt->crc << std::endl;
            oss << "Sequence: " << pkt->seq << std::endl;
            oss << "Command: " << pkt->cmd << std::endl;
            oss << "Data Length: " << pkt->data_len << std::endl;
            oss << "Data: ";
            const uint8_t* data_ptr = reinterpret_cast<const uint8_t*>(pkt.get() + 1);
            for (size_t i = 0; i < pkt->data_len; ++i) {
                oss << std::hex << static_cast<int>(data_ptr[i]) << " ";
            }
            oss << std::endl;

            logger.log(oss.str());
        }

        // 检查序号连续性
        if (!received_sequences.empty()) {
            auto it = received_sequences.begin();
            uint16_t prev_seq = *it;
            ++it;
            while (it != received_sequences.end()) {
                if (!isNextSequence(prev_seq, *it)) {
                    std::ostringstream oss;
                    oss << "Sequence gap detected: expected " << (prev_seq + 1) % 65536 << " but got " << *it << std::endl;
                    logger.log(oss.str());
                }
                prev_seq = *it;
                ++it;
            }
        }
    }
};

int main(int argc, char* argv[]) {
    if (argc < 2) {
        std::cerr << "Usage: " << argv[0] << " <port_name> [baud_rate] [ctsrts] [log_file]" << std::endl;
        return 1;
    }

    std::string port_name = argv[1];
    int baud_rate = 115200;
    bool ctsrts = false;
    std::string log_filename = "serial_test.log";

    if (argc >= 3) {
        int baud = std::stoi(argv[2]);
#ifdef _WIN32
        baud_rate = baud; // Windows下直接使用baud_rate
#else
        switch (baud) {
            case 9600: baud_rate = B9600; break;
            case 19200: baud_rate = B19200; break;
            case 38400: baud_rate = B38400; break;
            case 57600: baud_rate = B57600; break;
            case 115200: baud_rate = B115200; break;
            case 1000000: baud_rate = 1000000; break;
            default: std::cerr << "Unsupported baud rate. Using default 115200." << std::endl; break;
        }
#endif
    }

    if (argc >= 4) {
        ctsrts = std::stoi(argv[3]) != 0;
    }

    if (argc >= 5) {
        log_filename = argv[4];
    }

    try {
        SerialReceiver receiver(port_name, baud_rate, ctsrts, log_filename);
        std::this_thread::sleep_for(std::chrono::seconds(300));  // 模拟接收数据 30 秒
    } catch (const std::exception& e) {
        std::cerr << "异常: " << e.what() << std::endl;
    }
    return 0;
}
